package annotation.test;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.net.URL;
import java.util.*;

public class AnnotationOperator {

    static List<Class<?>> listClass = new ArrayList<>();//存放所有的类
    static List<File> listDirs = new ArrayList<>();
    //存放有目标注解的类 Test  在(1)过滤出来
    static Set<Component> Components = new HashSet<>();

    public AnnotationOperator() {
        Components.clear();

        List<Class<?>> classList = getClassesByPackageName("annotation.test");

        //(1)
        for (Class<?> clazz : classList) {
            String functionClass = Arrays.toString(clazz.getAnnotations());
            if (functionClass.contains("AnnotationClassTest")) {//过滤类注解
                Component component = new Component();
                Map<String, Method> map = new HashMap<>();
                //保存类注解别名值
                String AnnotationName = functionClass.substring(functionClass.indexOf("=") + 1, functionClass.length() - 2);
                component.setClazz(clazz);//保存类反射实例
                component.setAnnotationName(AnnotationName);
                Method[] methods = clazz.getDeclaredMethods();
                for (Method m : methods) {
                    String anName = Arrays.toString(m.getAnnotations());
                    if (anName.length() > 2) {//未使用注解标签的方法过滤掉
                        String methodName = m.getName();
                        Class<?>[] types = m.getParameterTypes();
                        try {
                            Method method = clazz.getDeclaredMethod(methodName, types);
                            for (Parameter p : method.getParameters()) {
                                System.out.println("参数名===========" + p.getName());
                            }
                        } catch (NoSuchMethodException | SecurityException e) {
                            e.printStackTrace();
                        }

                        String key = anName.substring(anName.indexOf("=") + 1, anName.length() - 2);
                        map.put(key, m);
                    }
                }

                component.setMethod(map);
                Components.add(component);

            }
        }

    }

    /**
     * 执行请求的方法
     *
     * @param method 方法名
     * @param params 参数
     */
    public void runMethod(String method, Object[] params) {
        String annotationName = method.split("\\.")[0];
        method = method.split("\\.")[1];
        for (Component c : Components) {
            try {
                if (c.getAnnotationName().equals(annotationName)) {
                    if (c.getMethod().containsKey(method)) {
                        c.getMethod().get(method).invoke(c.getClazz().newInstance(), params);
                    }
                }
            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException |
                     InstantiationException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 通过包名 扫描所有的类
     *
     * @param packageName 包名
     */
    private List<Class<?>> getClassesByPackageName(String packageName) {
        listDirs.clear();
        String path = packageName.replace('.', '/');
        try {
            Enumeration<URL> urls = AnnotationOperator.class.getClassLoader().getResources(path);
            while (urls.hasMoreElements()) {
                URL u = urls.nextElement();
                listDirs.add(new File(u.getFile()));
            }
            for (File f : listDirs) {
                if (f.isDirectory())
                    scanDirs(f);
            }
            listClass.clear();
            scanClasses();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return listClass;
    }

    /**
     * 获取所有目录《包》
     *
     * @param file 目录名
     */
    public void scanDirs(File file) {
        File[] files = file.listFiles();

        if (Objects.nonNull(files)) {

            Arrays.stream(files).forEach(f -> {
                if (f.isDirectory()) {
                    listDirs.add(f);
                    scanDirs(f);
                }
            });
        }
    }

    /**
     * 获取class 并反射出类 ,存到listClass
     */
    public void scanClasses() {
        listDirs.forEach(dir -> {
            if (dir.exists()) {
                Arrays.stream(Objects.requireNonNull(dir.listFiles())).forEach(file -> {
                    String className = file.getName();

                    if (className.endsWith(".class"))
                        try {
                            listClass.add(Class.forName("annotation.test." + className.substring(0, className.length() - 6)));
                        } catch (ClassNotFoundException e) {
                            e.printStackTrace();
                        }
                });
            }
        });
    }
}
